#include "Parser.hpp"

namespace Welp
{
  Parser::Parser()
  {
  }

  void Parser::DefaultErrorCallback(const string& message, const Location& location, void* userData)
  {
    printf("%s(%d): Welp Parse Error: %s\n", location.mOrigin.c_str(), location.mLine, message.c_str());
  }

  void Parser::ReadNextToken()
  {
    mTokenizer.ReadAndClassifyToken(&mToken);
  }

  void Parser::Error(const string& message)
  {
    throw Exception(message, ExceptionType::Parser, &mToken.mLocation);
  }

  bool Parser::Accept(TokenType::Enum type)
  {
    if (mToken.mType == type)
    {
      ReadNextToken();
      return true;
    }
    return false;
  }

  bool Parser::Expect(TokenType::Enum type, const char* optionalError)
  {
    if (Accept(type))
      return true;

    if (optionalError == nullptr)
      optionalError = "";

    string expected = mTokenizer.mTokenToString[type];

    Error(Format("Unexpected token: '%s', expected a '%s'. %s", mToken.mText.c_str(), expected.c_str(), optionalError));
    return false;
  }

  void Parser::ParseExpression()
  {
    if (Accept(TokenType::Function))
    {
      string name = mToken.mText;
      Expect(TokenType::Identifier);
      Expect(TokenType::BeginGroup);

      bool expectedArgument = false;

      // argument_list = argument_part | <empty>;
      // argument_part = identifier "," argument_part | identifier

      //for(;;)
      //{
      //  if (Accept(TokenType::Identifier))
      //  {
      //    if (Accept(TokenType::ArgumentSeparator))
      //    {
      //    }
      //  }
      //}

      Expect(TokenType::EndGroup);
    }

    Accept(TokenType::Number) ||
    Accept(TokenType::String) ||
    Accept(TokenType::True)   ||
    Accept(TokenType::False);
  }

  void Parser::ParseChunk()
  {
    while (ParseStatement());
  }

  void Parser::ParseBody()
  {
    Expect(TokenType::BeginScope);
    ParseChunk();
    Expect(TokenType::EndScope);
  }

  bool Parser::ParseStatement()
  {
    if (ParseFreeStatement())
    {
      return true;
    }
    else if (ParseDelimitedStatement())
    {
      return Expect(TokenType::StatementSeparator);
    }

    return false;
  }
  
  bool Parser::ParseFreeStatement()
  {
    return ParseIf() || ParseWhile();
  }

  bool Parser::ParseDelimitedStatement()
  {
    if (Accept(TokenType::Function))
    {
      return true;
    }

    return false;
  }

  bool Parser::ParseIf()
  {
    if (Accept(TokenType::If))
    {
      Expect(TokenType::BeginGroup);
      ParseExpression();
      Expect(TokenType::EndGroup);
      ParseBody();
      return true;
    }
    return false;
  }

  bool Parser::ParseWhile()
  {
    if (Accept(TokenType::While))
    {
      Expect(TokenType::BeginGroup);
      ParseExpression();
      Expect(TokenType::EndGroup);
      ParseBody();
      return true;
    }
    return false;
  }

  void Parser::Parse()
  {
    ReadNextToken();
    ParseBody();

    mTokenizer.mPosition = 0;
  }

  ParserBacktracker::ParserBacktracker(Parser* parser) :
    mParser(parser),
    mAccepted(false)
  {
    mTokenPositionStart = parser->mTokenizer.mPosition;
  }

  // Rejects the tokens at their position
  ParserBacktracker::~ParserBacktracker()
  {
    if (mAccepted == false)
    {
      mParser->mTokenizer.mPosition = mTokenPositionStart;
    }
  }

  // Tells the parser to accept the token at this position (always returns true)
  bool ParserBacktracker::Accept()
  {
    mAccepted = true;
    return true;
  }
}
